package org.xxpay.pay.channel.saaspay;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xxpay.core.common.constant.PayConstant;
import org.xxpay.core.common.domain.api.AbstractRes;
import org.xxpay.core.common.domain.api.ApiBuilder;
import org.xxpay.core.common.domain.api.PayRes;
import org.xxpay.core.common.domain.api.msg.QueryRetMsg;
import org.xxpay.core.common.util.*;
import org.xxpay.core.common.vo.DBApplicationConfig;
import org.xxpay.core.entity.PayOrder;
import org.xxpay.pay.channel.BasePayment;
import org.xxpay.pay.mq.BaseNotify4MchPay;

import java.net.URLEncoder;
import java.util.*;

import static org.xxpay.pay.channel.saaspay.SaaspayUtil.*;

/**
 * Saas支付
 *
 * @author: Zhixin
 * @date: 2024年3月01日09:07:38
 */

@Service
public class SaaspayPaymentService extends BasePayment {

    @Autowired
    public BaseNotify4MchPay baseNotify4MchPay;

    private static final MyLog _log = MyLog.getLog(SaaspayPaymentService.class);

    @Override
    public String getChannelName() {
        return SaaspayConfig.CHANNEL_NAME;
    }

    /**
     * 支付
     *
     * @param payOrder
     * @return
     */
    @Override
    public AbstractRes pay(PayOrder payOrder) {
        String channelId = payOrder.getChannelId();
        AbstractRes retObj;
        switch (channelId) {
            case SaaspayConfig.CHANNEL_NAME_H5PAY:
                retObj = h5Pay(payOrder);
                break;
            case SaaspayConfig.CHANNEL_NAME_WEBPAY:
                retObj = webPay(payOrder);
                break;
            case SaaspayConfig.CHANNEL_NAME_MINIPAY:
                retObj = miniPay(payOrder);
                break;
            default:
                return ApiBuilder.bizError("不支持的渠道[channelId=" + channelId + "]");
        }
        return retObj;
    }

    /**
     * H5支付
     *
     * @param payOrder
     * @return
     */
    public AbstractRes h5Pay(PayOrder payOrder) {
        SaaspayConfig saaspayConfig = new SaaspayConfig(getPayParam(payOrder));
        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);
        DBApplicationConfig dbConfig = getDBApplicationConfig();
        //1. 组建请求报文
        SaaspayUtil.H5PayBody reqBody = new SaaspayUtil.H5PayBody();
        reqBody.requestTimestamp = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS);
        reqBody.merOrderId = payOrder.getPayOrderId();
        reqBody.mid = saaspayConfig.getMid();
        reqBody.tid = saaspayConfig.getTid();
        reqBody.instMid = saaspayConfig.getInstMid();
        reqBody.totalAmount = payOrder.getAmount() + "";
        reqBody.notifyUrl = super.getNotifyUrl(getChannelName(), dbConfig);
        reqBody.returnUrl = super.getReturnUrl(getChannelName(), dbConfig);
        reqBody.orderDesc = payOrder.getBody();
        //2. 获取认证报文
        String authorization = "OPEN-FORM-PARAM";
        String nonce = RandomStrUtils.getInstance().getRandomString();
        String requestTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYYMMDDHHMMSS);
        _log.info("request body:\n" + reqBody);

        try {
            // 生成签名
            String signature = getSignature(saaspayConfig.getAppId(), saaspayConfig.getAppKey(), requestTime, nonce, reqBody.toString());
            String payUrl = "";
            String payType = saaspayConfig.getPayType();
            String reqUrl = saaspayConfig.getReqUrl();
            if ("ali".equals(payType)) {//支付宝
                payUrl = reqUrl + "/trade/h5-pay?";
            } else if ("wx".equals(payType)) {//微信
                payUrl = reqUrl + "/wxpay/h5-pay?";
            } else if ("ysf".equals(payType)) {//云闪付
                payUrl = reqUrl + "/uac/order?";
            } else if ("wxtomini".equals(payType)) {//微信转小程序
                payUrl = reqUrl + "/wxpay/h5-to-minipay?";
            }
            // 请求地址
            String toPayUrl = payUrl + "authorization=" + authorization + "&appId=" + saaspayConfig.getAppId()
                    + "&timestamp=" + requestTime + "&nonce=" + nonce + "&content=" + URLEncoder.encode(reqBody.toString(), "UTF-8")
                    + "&signature=" + URLEncoder.encode(signature, "UTF-8");
            _log.info("{}请求路径:{}", getChannelName(), toPayUrl);
            retObj.setPayJumpUrl(toPayUrl);      // 可以通过该地址跳转到支付中心界面完成支付(URL)
            StringBuffer payForm = new StringBuffer();
            payForm.append("<script>window.location.href = '" + toPayUrl + "';</script>");
            retObj.setPayUrl(payForm.toString());
            retObj.setPayJumpUrl(toPayUrl);
            retObj.setPayMethod(PayConstant.PAY_METHOD_JumpUrl);
            int updateCount = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            _log.info("[{}]更新订单状态为支付中:payOrderId={},payUrl={},result={}", getChannelName(), payOrder.getPayOrderId(), toPayUrl, updateCount);
            return retObj;
        } catch (Exception e) {
            _log.error(e, "");
            return ApiBuilder.bizError("操作失败!");
        }
    }


    /**
     * 公众号支付
     *
     * @param payOrder
     * @return
     */
    public AbstractRes webPay(PayOrder payOrder) {
        SaaspayConfig saaspayConfig = new SaaspayConfig(getPayParam(payOrder));
        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);
        DBApplicationConfig dbConfig = getDBApplicationConfig();
        //1. 组建请求报文
        SaaspayUtil.H5PayBody reqBody = new SaaspayUtil.H5PayBody();
        reqBody.requestTimestamp = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS);
        reqBody.merOrderId = payOrder.getPayOrderId();
        reqBody.mid = saaspayConfig.getMid();
        reqBody.tid = saaspayConfig.getTid();
        reqBody.instMid = saaspayConfig.getInstMid();
        reqBody.totalAmount = payOrder.getAmount() + "";
        reqBody.notifyUrl = super.getNotifyUrl(getChannelName(), dbConfig);
        reqBody.returnUrl = super.getReturnUrl(getChannelName(), dbConfig);
        reqBody.orderDesc = payOrder.getBody();
        reqBody.secureTransaction = "true";
        //2. 获取认证报文
        String authorization = "OPEN-FORM-PARAM";
        String nonce = RandomStrUtils.getInstance().getRandomString();
        String requestTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYYMMDDHHMMSS);
        _log.info("request body:\n" + reqBody);

        try {
            // 生成签名
            String signature = getSignature(saaspayConfig.getAppId(), saaspayConfig.getAppKey(), requestTime, nonce, reqBody.toString());
            String payUrl = "";
            String payType = saaspayConfig.getPayType();
            String reqUrl = saaspayConfig.getReqUrl();
            if ("ali".equals(payType)) {//支付宝
                payUrl = reqUrl + "/trade/create?";
            } else if ("wxhd".equals(payType)) {//微信
                payUrl = reqUrl + "/wx/unified-order?";
            } else if ("ysf".equals(payType)) {//云闪付
                payUrl = reqUrl + "/acp/js-pay?";
            } else if ("wxqt".equals(payType)) {//微信转小程序
                payUrl = reqUrl + "/webpay/pay?";
            }
            // 请求地址
            String toPayUrl = payUrl + "authorization=" + authorization + "&appId=" + saaspayConfig.getAppId()
                    + "&timestamp=" + requestTime + "&nonce=" + nonce + "&content=" + URLEncoder.encode(reqBody.toString(), "UTF-8")
                    + "&signature=" + URLEncoder.encode(signature, "UTF-8");
            _log.info("{}请求路径:{}", getChannelName(), toPayUrl);
            retObj.setPayJumpUrl(toPayUrl);      // 可以通过该地址跳转到支付中心界面完成支付(URL)
            StringBuffer payForm = new StringBuffer();
            payForm.append("<script>window.location.href = '" + toPayUrl + "';</script>");
            retObj.setPayUrl(payForm.toString());
            retObj.setPayJumpUrl(toPayUrl);
            retObj.setPayMethod(PayConstant.PAY_METHOD_JumpUrl);
            int updateCount = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            _log.info("[{}]更新订单状态为支付中:payOrderId={},payUrl={},result={}", getChannelName(), payOrder.getPayOrderId(), toPayUrl, updateCount);
            return retObj;
        } catch (Exception e) {
            _log.error(e, "");
            return ApiBuilder.bizError("操作失败!");
        }
    }

    /**
     * 小程序支付
     *
     * @param payOrder
     * @return
     */
    public AbstractRes miniPay(PayOrder payOrder) {
        SaaspayConfig saaspayConfig = new SaaspayConfig(getPayParam(payOrder));
        PayRes retObj = ApiBuilder.buildSuccess(PayRes.class);
        DBApplicationConfig dbConfig = getDBApplicationConfig();
        //1. 组建请求报文
        SaaspayUtil.H5PayBody reqBody = new SaaspayUtil.H5PayBody();
        reqBody.requestTimestamp = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS);
        reqBody.merOrderId = payOrder.getPayOrderId();
        reqBody.mid = saaspayConfig.getMid();
        reqBody.tid = saaspayConfig.getTid();
        reqBody.instMid = saaspayConfig.getInstMid();
        reqBody.totalAmount = payOrder.getAmount() + "";
        reqBody.notifyUrl = super.getNotifyUrl(getChannelName(), dbConfig);
        reqBody.returnUrl = super.getReturnUrl(getChannelName(), dbConfig);
        reqBody.orderDesc = payOrder.getBody();
        //2. 获取认证报文
        String authorization = "OPEN-FORM-PARAM";
        String nonce = RandomStrUtils.getInstance().getRandomString();
        String requestTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYYMMDDHHMMSS);
        _log.info("request body:\n" + reqBody);

        try {
            // 生成签名
            String signature = getSignature(saaspayConfig.getAppId(), saaspayConfig.getAppKey(), requestTime, nonce, reqBody.toString());
            String payUrl = "";
            String payType = saaspayConfig.getPayType();
            String reqUrl = saaspayConfig.getReqUrl();
            if ("ali".equals(payType)) {//支付宝
                payUrl = reqUrl + "/trade/h5-pay?";
            } else if ("wx".equals(payType)) {//微信
                payUrl = reqUrl + "/wxpay/h5-pay?";
            } else if ("ysf".equals(payType)) {//云闪付
                payUrl = reqUrl + "/uac/order?";
            } else if ("wxtomini".equals(payType)) {//微信转小程序
                payUrl = reqUrl + "/wxpay/h5-to-minipay?";
            }
            // 请求地址
            String toPayUrl = payUrl + "authorization=" + authorization + "&appId=" + saaspayConfig.getAppId()
                    + "&timestamp=" + requestTime + "&nonce=" + nonce + "&content=" + URLEncoder.encode(reqBody.toString(), "UTF-8")
                    + "&signature=" + URLEncoder.encode(signature, "UTF-8");
            _log.info("{}请求路径:{}", getChannelName(), toPayUrl);
            retObj.setPayJumpUrl(toPayUrl);      // 可以通过该地址跳转到支付中心界面完成支付(URL)
            StringBuffer payForm = new StringBuffer();
            payForm.append("<script>window.location.href = '" + toPayUrl + "';</script>");
            retObj.setPayUrl(payForm.toString());
            retObj.setPayJumpUrl(toPayUrl);
            retObj.setPayMethod(PayConstant.PAY_METHOD_JumpUrl);
            int updateCount = commonService.payOrderService.updateStatus4Ing(payOrder.getPayOrderId(), null);
            _log.info("[{}]更新订单状态为支付中:payOrderId={},payUrl={},result={}", getChannelName(), payOrder.getPayOrderId(), toPayUrl, updateCount);
            return retObj;
        } catch (Exception e) {
            _log.error(e, "");
            return ApiBuilder.bizError("操作失败!");
        }
    }

    /**
     * 查询订单
     *
     * @param payOrder
     * @return
     */
    @Override
    public QueryRetMsg query(PayOrder payOrder) {
        String logPrefix = "[" + getChannelName() + "主动查单]";
        SaaspayConfig saaspayConfig = new SaaspayConfig(getPayParam(payOrder));
        SaaspayUtil.QueryBody reqBody = new SaaspayUtil.QueryBody();
        //1. 组建请求报文
        reqBody.requestTimestamp = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS);
        reqBody.merOrderId = payOrder.getPayOrderId();
        reqBody.mid = saaspayConfig.getMid();
        reqBody.tid = saaspayConfig.getTid();
        reqBody.instMid = saaspayConfig.getInstMid();
        String nonce = RandomStrUtils.getInstance().getRandomString();
        String requestTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYYMMDDHHMMSS);
        _log.info("{}request body:\n{}", logPrefix, reqBody);
        //2. 获取认证报文，timestamp为当前日期，老旧日期无法请求成功
        String authorization = SaaspayUtil.getAuthorization(saaspayConfig.getAppId(), saaspayConfig.getAppKey(), requestTime, nonce, reqBody.toString());
        _log.info("{}authorization:\n{}", logPrefix, authorization);
        //3. 发送http请求，并解析返回信息
        String queryUrl = saaspayConfig.getReqUrl() + "/query";
        String response = queryRequest(queryUrl, authorization, reqBody.toString());
        _log.info("{}response:\n{}", logPrefix, response);
        return QueryRetMsg.waiting();  //支付中
    }


    public static void main(String[] args) throws Exception {

        String appid = "8a81c1be89b6cc1f018e5b02fcd21ca2";
        String appkey = "5239e2a3ca674ac998f7848f47903b4a";
        String url = "https://test-api-open.chinaums.com/v1/netpay/trade/h5-pay";
        String testUrl = "https://api-mop.chinaums.com/v1/netpay/wxpay/h5-to-minipay";

        //1. 组建请求报文
        String nonce = RandomStrUtils.getInstance().getRandomString();
        String requestTime = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYYMMDDHHMMSS);
        SaaspayUtil.H5PayBody reqBody = new SaaspayUtil.H5PayBody();
        reqBody.requestTimestamp = DateUtil.date2Str(new Date(), DateUtil.FORMAT_YYYY_MM_DD_HH_MM_SS);
        reqBody.merOrderId = "386B" + requestTime;
        reqBody.mid = "89821025734895D";
        reqBody.tid = "24031212";
        reqBody.instMid = "H5DEFAULT";
        reqBody.totalAmount = "1";
        reqBody.returnUrl = "https://admin.jiataiwu.top//help/taotu.html";
        System.out.println("request body:\n" + reqBody);

        //2. 获取认证报文
        String authorization = "OPEN-FORM-PARAM";
        System.out.println("authorization:\n" + authorization);

        String signature = getSignature(appid, appkey, requestTime, nonce, reqBody.toString());

        String URL = testUrl + "?" + "authorization=" + authorization + "&appId=" + appid
                + "&timestamp=" + requestTime + "&nonce=" + nonce + "&content=" + URLEncoder.encode(reqBody.toString(), "UTF-8")
                + "&signature=" + URLEncoder.encode(signature, "UTF-8");
        System.out.println("URL:" + URL);
        //3. 发送http请求，并解析返回信息
        String response = h5Request(URL);
        System.out.println("response:\n" + response);
    }

}
